前一篇使用了 @Input,來向元件傳入變數,今天我們要用 @Output 對元件外傳出變數。
我們之前做了一個登入的功能,卻只能從 AccountManagerComponent 來控制登入及登出的狀態,這是非常不合理的。所以今天我想實作,在子元件按下 Login 時,可以傳送一個請求,更改 AccountManagerComponent 的 status。
@Output 和 @Input 的基本概念相似,可以當成定義一個出口,送出event,所以我們一樣宣告一個變數,我命名為 loginRequest 並且在前面加上 @Output:
// login.component.ts
@Output() loginRequest;
然後,我們需要初始化這個變數,我們給他一個 EventEmitter,可以當成是,這個變數會往 Component 外丟出 event:
@Output() loginRequest = new EventEmitter<any>();
<any> 這個地方要放當 EventEmitter 觸發時,要送出資料的型別,any 就是任意型別都可以。在我這個範例,只會丟出 boolean資料,所以其實填入 <boolean> 會比較嚴謹。
這邊注意在打 EventEmitter 時,由於我們這份 ts 還沒有 import 過這個模組,此時 VSCODE 會出現提示字,並且會幫我們 import。這時請注意,我們要選擇的是從 @angular/core import的 EventEmitter。

操作正確的話,最上面的 import 應該會像這樣:
此時我們已經定義好對外的 @Output() 介面了,切到 account-manager.component.html,我們已經可以在 <app-login></app-login>下用 loginRequest 做 Event Binding。
<app-login [loginStatus]="status" (loginRequest)=""></app-login>
那麼我們現在來實作,從 LoginComponent 要送出的事件與資料,我先決定好我要的 function:loginAction 負責登入,logout 負責登出。
// login.component.ts
loginAction() {
}
logout() {
}
然後綁定到我們 login.component.html 裡面的兩個 button:

// login.component.html
<div *ngIf="!loginStatus">
...
<input type="submit" value="Login" (click)="loginAction()">
</div>
<div *ngIf="loginStatus">
<button (click)="logout()">Logout</button>
</div>
現在 loginAction() 和 logout() 已經和login.component.html 內的 button 做完 Event binding,按下 button 就會分別觸發 loginAction() 和 logout()。
接者定義我按下這兩個 button 時, @Output()要送什麼資料出去。
我用剛剛宣告的 loginRequest,用 emit 這個function,發射一個 boolean 的物件。
登入時我發射 true ,登出時我發射 false。而這裡為求簡單,就不做驗證帳密相關的功能了。
// login.component.ts
loginAction() {
this.loginRequest.emit(true);
}
logout() {
this.loginRequest.emit(false);
}
現在的 AccountManagerComponent 已經可以在 <app-login> 丟出 true 跟 false,
// account-manager.component.html
<app-login ... (loginRequest)=""></app-login>
那我們要用一個 function 來接這個參數,或著說,當 loginRequest 發出 emit 時,我要觸發一個 function。所以我們需要在 account-manager.component.ts 中設計一個 function,被 loginRequest 觸發。
// account-manager.component.ts
loginCheck($event) {
this.status = $event;
}
// account-manager.component.html
<app-login ... (loginRequest)="loginCheck($event)" ></app-login>
這邊的 $event 就會接到從 loginRequest emit 出來的 true 或 false。並且直接改變 status 的登入狀態。
覺得疑惑的話,可以在 loginCheck($event) 中加入 console.log(),將 $event 印出來看看:
console.log('$event: ' + $event);

現在按下 Login、Logout 的 button ,就可以透過 @Output 發出事件,改變登入狀態的 status ,並且修改 Login、 Logout 的顯示與否了。

按下 Login:
再按下 Logout 又會回到 Login。
資料流大致上是這樣
還有在使用 @Input() 、@Output() 這兩個 Decorator 時,可以在括號中填入其他名字來 rename,就可以用 rename 過的名字進行 Property Binding。
舉例之前的 loginStatus。
@Input() loginStatus;
可以 rename 成 sss 或任何名字 :
@Input('sss') loginStatus;
那我們就必須用 rename 過的名字 Binding:
<app-login [sss]="status"></app-login>
但這個 rename 的功能,Angular 是不推薦使用,所以還是盡量少用吧。